/*
Copyright (C) 2008 Matthew Perry

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This libary/program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using BaseTools.Configuration;
using BaseTools.Configuration.Parsers;
using BaseTools.Helpers;

namespace BaseTools.XS
{
	/// <summary>
	/// A settings manager for XBaseTools
	/// </summary>
	public class XSettings
	{
		private string xprogram;
		
		/// <summary>
		/// Create an XSettings instance
		/// </summary>
		/// <param name="program">The program name to manage</param>
		public XSettings(string program)
		{
			xprogram = program;
		}
		
		/// <summary>
		///The root settings folder
		/// </summary>
		public static string SettingsFolder
		{
			get
			{
				return IOHelper.RelativeTo(Environment.GetFolderPath(Environment.SpecialFolder.Personal).ToString(), "XSettings");
			}
		}
		
		
		/// <summary>
		/// The root global settings folder
		/// </summary>
		public static string GlobalSettingsFolder
		{
			get
			{
				return IOHelper.RelativeTo(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData).ToString(), "XSettings");
			}
		}
		
		/// <summary>
		/// The root settings folder as a DirectoryInfo
		/// </summary>
		public static DirectoryInfo SettingsDirectory
		{
			get
			{
				return new DirectoryInfo(SettingsFolder);
			}
		}
		/// <summary>
		/// The root global settings folder as a DirectoryInfo
		/// </summary>
		public static DirectoryInfo GlobalSettingsDirectory
		{
			get
			{
				return new DirectoryInfo(GlobalSettingsFolder);
			}
		}
		
		/// <summary>
		/// Gets a list of all the programs in the folder
		/// </summary>
		/// <returns>A list of all the programs as XSettings</returns>
		public static XSettings[] GetPrograms()
		{
			DirectoryInfo[] di = SettingsDirectory.GetDirectories();
			XSettings[] xs = new XSettings[di.Length];
			
			for(int i=0;i<di.Length;i++)
			{
				xs[i] = new XSettings(di[i].Name);
			}
			return xs;
		}
		
		/// <summary>
		/// Gets a list of all the programs in the global folder
		/// </summary>
		/// <returns>A list of all the programs as XSettings</returns>
		public static XSettings[] GetGlobalPrograms()
		{
			DirectoryInfo[] di = GlobalSettingsDirectory.GetDirectories();
			XSettings[] xs = new XSettings[di.Length];
			
			for(int i=0;i<di.Length;i++)
			{
				xs[i] = new XSettings(di[i].Name);
			}
			return xs;
		}
		
		/// <summary>
		/// Whether the settings folder exists
		/// </summary>
		public static bool SettingsExists
		{
			get
			{
				return new DirectoryInfo(SettingsFolder).Exists;
			}
		}
		
		/// <summary>
		/// Ensure that the root settings folder exists
		/// </summary>
		public static void EnsureSettings()
		{
			try
			{
				if (!SettingsDirectory.Exists)
					SettingsDirectory.Create();
				if (!GlobalSettingsDirectory.Exists)
					GlobalSettingsDirectory.Create();
			}
			catch(Exception)
			{
			}
		}
		
		/// <summary>
		/// The program settings folder
		/// </summary>
		public string ProgramFolder
		{
			get
			{
				return IOHelper.RelativeTo(SettingsFolder, xprogram);
			}
		}
		
		/// <summary>
		/// The program settings folder as a DirectoryInfo
		/// </summary>
		public DirectoryInfo ProgramDirectory
		{
			get
			{
				return new DirectoryInfo(ProgramFolder);
			}
		}
		
		/// <summary>
		/// The global program settings folder
		/// </summary>
		public string GlobalProgramFolder
		{
			get
			{
				return IOHelper.RelativeTo(GlobalSettingsFolder, xprogram);
			}
		}
		
		/// <summary>
		/// The global program settings folder as a DirectoryInfo
		/// </summary>
		public DirectoryInfo GlobalProgramDirectory
		{
			get
			{
				return new DirectoryInfo(GlobalProgramFolder);
			}
		}
		
		/// <summary>
		/// Whether this program folder exists
		/// </summary>
		public bool Exists
		{
			get
			{
				return ProgramDirectory.Exists;
			}
		}
		
		/// <summary>
		/// Ensures that XSettings and this program exist
		/// </summary>
		public void EnsureProgram()
		{
			XSettings.EnsureSettings();
			this.Create();
		}
		
		/// <summary>
		/// Ensures that XSettings and this program (including global) exist
		/// </summary>
		public void EnsureProgramGlobal()
		{
			try
			{
				XSettings.EnsureSettings();
				this.Create();
				if (!GlobalProgramDirectory.Exists)
					GlobalProgramDirectory.Create();
			}
			catch(Exception)
			{
			}
		}
		
		/// <summary>
		/// Creates this folder if it doesn't exist
		/// </summary>
		public void Create()
		{
			if (!Exists)
				ProgramDirectory.Create();
		}
		
		/// <summary>
		/// Deletes this folder if it exists
		/// </summary>
		public void Delete()
		{
			if (Exists)
				ProgramDirectory.Delete(true);
		}
		
		/// <summary>
		/// Get the files in the program directory
		/// </summary>
		/// <returns></returns>
		public FileInfo[] GetFiles()
		{
			return ProgramDirectory.GetFiles();
		}
		
		/// <summary>
		/// Get te files in the program directory
		/// </summary>
		/// <param name="searchPattern">The pattern to search for</param>
		/// <returns></returns>
		public FileInfo[] GetFiles(string searchPattern)
		{
			return ProgramDirectory.GetFiles(searchPattern);
		}
		
		/// <summary>
		/// Get the files in the program directory
		/// </summary>
		/// <param name="searchPattern">The pattern to search for</param>
		/// <param name="searchOption">The search option</param>
		/// <returns></returns>
		public FileInfo[] GetFiles(string searchPattern, SearchOption searchOption)
		{
			return ProgramDirectory.GetFiles(searchPattern, searchOption);
		}
		
		/// <summary>
		/// Get the directories in the program directory
		/// </summary>
		/// <returns></returns>
		public DirectoryInfo[] GetDirectories()
		{
			return ProgramDirectory.GetDirectories();
		}
		
		/// <summary>
		/// Get the directories in the program directory
		/// </summary>
		/// <param name="searchPattern">The pattern to search for</param>
		/// <returns></returns>
		public DirectoryInfo[] GetDirectories(string searchPattern)
		{
			return ProgramDirectory.GetDirectories(searchPattern);
		}
		
		/// <summary>
		/// Get the directories in the program directory
		/// </summary>
		/// <param name="searchPattern">The pattern to search for</param>
		/// <param name="searchOption">The search option</param>
		/// <returns></returns>
		public DirectoryInfo[] GetDirectories(string searchPattern, SearchOption searchOption)
		{
			return ProgramDirectory.GetDirectories(searchPattern, searchOption);
		}
		
		/// <summary>
		/// Gets the filename relative to this program settings
		/// </summary>
		/// <param name="s">The filename, if prefixed with a # then it uses the global xsettings folder</param>
		/// <returns>The filename relative to this</returns>
		public string RelativeTo(string s)
		{
			if (s.StartsWith("#"))
			{
				return IOHelper.RelativeTo(GlobalProgramFolder, s.Substring(1));
			}
			else
			{
				return IOHelper.RelativeTo(ProgramFolder, s);
			}
		}
		
		private string ChooseInList(string[] str)
		{
			foreach(string s in str)
			{
				if (new FileInfo(RelativeTo(s)).Exists)
					return s;
			}
			
			return null;
		}
		private string ReadDict(Dictionary<string, string> dict, string key)
		{
			return dict.ContainsKey(key) ? dict[key] : "";
		}
		
		/// <summary>
		/// The image for the program
		/// </summary>
		public Image ProgramImage
		{
			get
			{
				string fileName = ChooseInList(new string[] {"ProgramImage.png", "ProgramImage.bmp", "ProgramImage.jpg", "ProgramImage.jpeg"});
				
				if (fileName != null)
					return new Bitmap(RelativeTo(fileName));
				else
					return null;
			}
			set
			{
				string fileName = ChooseInList(new string[] {"ProgramImage.png", "ProgramImage.bmp", "ProgramImage.jpg", "ProgramImage.jpeg"});
				
				if (fileName == null)
					fileName = "ProgramImage.png";
				
				value.Save(RelativeTo(fileName));
			}
		}
		
		/// <summary>
		/// The program info for the program
		/// </summary>
		public XSInfo ProgramInfo
		{
			get
			{
				if (new FileInfo(RelativeTo("ProgramInfo.xbt")).Exists)
				{
					Dictionary<string, string> dict =
						GenericConverter.ReadSection(new GeneralConfig().LoadConfiguration(RelativeTo("ProgramInfo.xbt")));
					
					return new XSInfo(ReadDict(dict, "Name"), ReadDict(dict, "Author"), ReadDict(dict, "Description"), ReadDict(dict, "Launch"));
				}
				else if (new FileInfo(RelativeTo("ProgramInfo.cfg")).Exists)
				{
					Dictionary<string, string> dict =
						GenericConverter.ReadSection(new GeneralConfig().LoadConfiguration(RelativeTo("ProgramInfo.cfg")));
					
					return new XSInfo(ReadDict(dict, "Name"), ReadDict(dict, "Author"), ReadDict(dict, "Description"), ReadDict(dict, "Launch"));
				}
				else
				{
					return new XSInfo("", "", "", "");
				}
			}
			set
			{
				ConfigList list = new ConfigList();
				
				list.AddString("Name", value.Name);
				list.AddString("Author", value.Author);
				list.AddString("Description", value.Description);
				list.AddString("Launch", value.Launch);
				
				new GeneralConfig().SaveConfiguration(RelativeTo("ProgramInfo.xbt"), list);
			}
		}
		
		/// <summary>
		/// The directory name of the program
		/// </summary>
		public string Name
		{
			get
			{
				return xprogram;
			}
		}
	}
}
